﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

//https://www.redblobgames.com/grids/hexagons/
public class HexGrid
{
    // 目前只考虑POINT格式，
    public enum HexFormat
    {
        POINTY,
        FLAT,
    }

    public enum RotationAngle
    {
        NONE,
        RIGHT_60,
        RIGHT_120,
        INVERSE,
        LEFT_120,
        LEFT_60,
    }

    public const float SIN_30 = 0.866025404f;// = sin(PI/6)
    public const float SIN_60 = 1.047197551f;// = sin(PI/3)
    public static Vector3 XAxisN = new Vector3(Mathf.Sin(1 *   SIN_60), Mathf.Cos(1 * SIN_60), 0).normalized;
    public static Vector3 YAxisN = new Vector3(Mathf.Sin(Mathf.PI), Mathf.Cos(Mathf.PI), 0).normalized;
    public static Vector3 ZAxisN = new Vector3(Mathf.Sin(-1 * SIN_60), Mathf.Cos(-1 * SIN_60), 0).normalized; 
    public static Vector3 XAxisT = new Vector3(Mathf.Sin(-1*   SIN_30), Mathf.Cos(-1*SIN_30), 0).normalized;
    public static Vector3 YAxisT = new Vector3(Mathf.Sin(1*    SIN_30), Mathf.Cos(1*SIN_30), 0).normalized;
    public static Vector3 ZAxisT = new Vector3(Mathf.Sin(1 *   SIN_60 + SIN_30), Mathf.Cos(1 * SIN_60 + SIN_30), 0).normalized;
    public static float Radius = 1;
    public static float HorizontalScale = 1;
    public static float VerticalScale = 1;
    public static HexFormat Format = HexFormat.POINTY;

    private static Vector3 m_DescartesCenterPoint = new Vector3(0,0,0);
    private Vector3Int m_Position;
    private float m_Height = 0.01f;

    public static HexGrid[] m_Directions = new HexGrid[] {new HexGrid(+1, 0, -1), new HexGrid(+1, -1, 0), new HexGrid(0, -1, +1),
                                                 new HexGrid(-1, 0, +1), new HexGrid(-1, +1, 0), new HexGrid(0, +1, -1)};
    /// <summary>
    /// 获取两个六边形横向的间距，（同样也是六边形的宽度）
    /// </summary>
    /// <returns></returns>
    public static float GetHorizontalSpacing()
    {
        return Mathf.Sqrt(3) * Radius;
    }
    public static float GetVerticalSpacing()
    {
        return 2*Radius*(3f/4f);
    }
    public static HexGrid GetRing(HexGrid center, int radius, int index)
    {
        if(index > radius * 6)
        {
            return new HexGrid();
        }
        var i = (int)((index) / radius);
        var newHexGrid = new HexGrid();
        int nextDirectionI = (i+2)%6;
        newHexGrid = center + (m_Directions[i] * radius) + m_Directions[nextDirectionI] * (index % radius);
        return newHexGrid;
    }
    public static HexGrid operator + (HexGrid a, HexGrid b)
    {
        var hexGrid = new HexGrid();
        hexGrid.m_Position.x = a.m_Position.x + b.m_Position.x;
        hexGrid.m_Position.y = a.m_Position.y + b.m_Position.y;
        hexGrid.m_Position.z = a.m_Position.z + b.m_Position.z;
        return hexGrid;
    }
    public static HexGrid operator -(HexGrid a, HexGrid b)
    {
        var hexGrid = new HexGrid();
        hexGrid.m_Position.x = a.m_Position.x - b.m_Position.x;
        hexGrid.m_Position.y = a.m_Position.y - b.m_Position.y;
        hexGrid.m_Position.z = a.m_Position.z - b.m_Position.z;
        return hexGrid;
    }
    public static HexGrid operator *(HexGrid a, int b)
    {
        var hexGrid = new HexGrid();
        hexGrid.m_Position.x = a.m_Position.x * b;
        hexGrid.m_Position.y = a.m_Position.y * b;
        hexGrid.m_Position.z = a.m_Position.z * b;
        return hexGrid;
    }

    public HexGrid() 
    { 
    }
    public HexGrid(Vector3Int position)
    {
        Init(position);
    }
    public HexGrid(Vector2Int position)
    {
        Init(position);
    }
    public HexGrid(int x, int y, int z)
    {
        Init(new Vector3Int(x, y, z));
    }
    public HexGrid(int row, int cloumn)
    {
        Init(new Vector2Int(row, cloumn));
    }
    public void Rotation(RotationAngle rotation)
    {
        switch(rotation)
        {
            case RotationAngle.LEFT_60:
                m_Position = new Vector3Int(-m_Position.y, -m_Position.z, -m_Position.x);
                break;
            case RotationAngle.LEFT_120:
                m_Position = new Vector3Int(m_Position.z, m_Position.x, m_Position.y);
                break;
            case RotationAngle.RIGHT_60:
                m_Position = new Vector3Int(-m_Position.z, -m_Position.x, -m_Position.y);
                break;
            case RotationAngle.RIGHT_120:
                m_Position = new Vector3Int(m_Position.y, m_Position.z, m_Position.x);
                break;
            case RotationAngle.INVERSE:
                m_Position = new Vector3Int(-m_Position.x, -m_Position.y, -m_Position.z);
                break;
        }
    }
    /// \brief  获取笛卡尔坐标，返回的是中心点
    public Vector3 GetDescartesPosition(float radius=-1)
    {
        if (radius < 0)
            radius = Radius;
        Vector3 outputPosition = new Vector3();
        if(Format == HexFormat.FLAT)
        {
            outputPosition += XAxisT * (m_Position.x * (radius * 1.0f));//x
            outputPosition += YAxisT * (m_Position.y * (radius * 1.0f));//y
            outputPosition += ZAxisT * (m_Position.z * (radius * 2f));//z
        }
        else if(Format == HexFormat.POINTY)
        {
            //var xAxis = new Vector3(XAxisN.x * HorizontalScale, XAxisN.y, XAxisN.z).normalized;
            //var yAxis = new Vector3(YAxisN.x * HorizontalScale, YAxisN.y, YAxisN.z).normalized;
            //var zAxis = (new Vector3(ZAxisN.x, XAxisN.y, XAxisN.z) * VerticalScale).normalized;
            outputPosition += XAxisN * (m_Position.x * (radius * HorizontalScale ));//x
            outputPosition += YAxisN * (m_Position.y * (radius * VerticalScale));//y
            outputPosition += ZAxisN * (m_Position.z * (radius * HorizontalScale));//z
        }

        outputPosition += m_DescartesCenterPoint;
        return outputPosition;
    }
    public Vector3 GetCornerPosition(int index, float radius = -1)
    {
        if (radius == -1)
            radius = Radius;
        index += 6;
        var descartesPosition = GetDescartesPosition(radius);
        descartesPosition += new Vector3(Mathf.Sin(index * SIN_60), Mathf.Cos(index * SIN_60), 0) * radius;
        descartesPosition.z = m_Height;
        return descartesPosition;
    }
    public Vector3Int GetPosition()
    {
        return m_Position;
    }
    public Vector2Int GetPositionOddr()
    {
        var col = m_Position.x + (m_Position.y - (m_Position.y & 1)) / 2;
        var row = m_Position.y;
        return new Vector2Int(col, row);
    }
    protected void Init(Vector3Int position)
    {
        m_Position = position;
    }
    protected void Init(Vector2Int position)
    {
        if (Format == HexFormat.FLAT)
        {
        }
        else if (Format == HexFormat.POINTY)
        {
            int x = position.x - (position.y - (position.y & 1)) / 2;
            int y = position.y;
            int z = -x - y;
            m_Position = new Vector3Int(x, y, z);
        }
    }

};